<template>
  <view class="relative" :style="{ zIndex }">
    <!-- 遮罩层 -->
    <view 
      class="fixed inset-0 bg-black/60 transition-all duration-300" 
      :class="{ 'opacity-0 invisible': !isShow, 'opacity-100 visible': isShow }" 
      :style="{ zIndex: getMaskZIndex }"
      @touchmove.stop.prevent="stop" 
      catchtouchmove="stop" 
      @tap="maskClick"
    ></view>
    
    <!-- 选择器容器 -->
    <view 
      class="fixed left-0 bottom-0 w-full transition-all duration-300 transform bg-surface dark:bg-surface-dark"
      :class="{ 'translate-y-full opacity-0': !isShow, 'translate-y-0 opacity-100': isShow }"
      :style="{ zIndex: getPickerZIndex }"
    >
      <!-- 选择器头部 -->
      <view 
        class="w-full px-10 h-[90rpx] flex justify-between items-center relative"
        :class="{ 'rounded-t-[20rpx]': radius }"
        @touchmove.stop.prevent="stop" 
        catchtouchmove="stop"
      >
        <!-- 取消按钮 -->
        <view 
          class="py-4 active:opacity-50 transition-opacity duration-150" 
          :style="{ color: cancelColor || 'var(--color-on-surface, #888888)' }" 
          @tap="hide"
        >取消</view>
        
        <!-- 标题 -->
        <view 
          class="flex-1 px-[30rpx] text-center truncate"
          :style="{
            fontSize: titleSize + 'rpx',
            color: titleColor || 'var(--color-on-surface, #333333)'
          }"
        >{{ title }}</view>
        
        <!-- 确定按钮 -->
        <view 
          class="py-4 active:opacity-50 transition-opacity duration-150" 
          :style="{ color: getColor }" 
          @tap="btnFix"
        >确定</view>
        
        <!-- 底部边框 -->
        <view class="absolute bottom-0 left-0 right-0 border-b border-gray-200 dark:border-gray-700 transform scale-y-50"></view>
      </view>
      
      <!-- 单位头部 -->
      <view 
        v-if="unitTop"
        class="w-full h-[52rpx] flex items-center justify-between text-[26rpx] leading-[26rpx] relative z-2 bg-surface dark:bg-surface-dark"
        :style="{ backgroundColor: unitBackground || 'var(--color-surface, #FFFFFF)' }"
      >
        <view class="flex-1 text-center text-gray-600 dark:text-gray-400" v-if="type < 4 || type == 7 || type == 8">年</view>
        <view class="flex-1 text-center text-gray-600 dark:text-gray-400" v-if="(type < 4 && type > 0) || type == 7 || type == 8">月</view>
        <view class="flex-1 text-center text-gray-600 dark:text-gray-400" v-if="type == 1 || type == 2 || type == 7 || type == 8">日</view>
        <view class="flex-1 text-center text-gray-600 dark:text-gray-400" v-if="type == 1 || type == 4 || type == 5 || type == 7 || type == 8">时</view>
        <view class="flex-1 text-center text-gray-600 dark:text-gray-400" v-if="(type == 1 || type > 3) && type != 8">分</view>
        <view class="flex-1 text-center text-gray-600 dark:text-gray-400" v-if="type > 4 && type != 8">秒</view>
        
        <!-- 底部阴影 -->
        <view class="absolute bottom-0 left-0 right-0 h-4 bg-gradient-to-b from-transparent to-gray-100/20 dark:to-gray-800/20"></view>
      </view>
      
      <!-- 选择器主体 -->
      <view 
        @touchstart.stop="pickerstart" 
        class="w-full"
        :style="{
          backgroundColor: bodyBackground || 'var(--color-surface, #FFFFFF)',
          height: height + 'rpx'
        }"
      >
        <picker-view 
          :key="type" 
          :immediate-change="immediate" 
          :value="value" 
          @change="change"
          class="h-full"
        >
          <!-- 年份列 -->
          <picker-view-column v-if="type < 4 || type == 7 || type == 8">
            <view 
              class="flex items-center justify-center text-gray-900 dark:text-gray-100"
              :class="{ 'text-[32rpx]': !unitTop && type == 7, 'text-[36rpx]': !((!unitTop && type == 7)) }"
              v-for="(item, index) in years" 
              :key="index"
            >
              {{ item }}
              <text class="text-[24rpx] pl-[8rpx] text-gray-500 dark:text-gray-400" v-if="!unitTop">年</text>
            </view>
          </picker-view-column>
          
          <!-- 月份列 -->
          <picker-view-column v-if="(type < 4 && type > 0) || type == 7 || type == 8">
            <view 
              class="flex items-center justify-center text-gray-900 dark:text-gray-100"
              :class="{ 'text-[32rpx]': !unitTop && type == 7, 'text-[36rpx]': !((!unitTop && type == 7)) }"
              v-for="(item, index) in months" 
              :key="index"
            >
              {{ formatNum(item) }}
              <text class="text-[24rpx] pl-[8rpx] text-gray-500 dark:text-gray-400" v-if="!unitTop">月</text>
            </view>
          </picker-view-column>
          
          <!-- 日期列 -->
          <picker-view-column v-if="type == 1 || type == 2 || type == 7 || type == 8">
            <view 
              class="flex items-center justify-center text-gray-900 dark:text-gray-100"
              :class="{ 'text-[32rpx]': !unitTop && type == 7, 'text-[36rpx]': !((!unitTop && type == 7)) }"
              v-for="(item, index) in days" 
              :key="index"
            >
              {{ formatNum(item) }}
              <text class="text-[24rpx] pl-[8rpx] text-gray-500 dark:text-gray-400" v-if="!unitTop">日</text>
            </view>
          </picker-view-column>
          
          <!-- 小时列 -->
          <picker-view-column v-if="type == 1 || type == 4 || type == 5 || type == 7 || type == 8">
            <view 
              class="flex items-center justify-center text-gray-900 dark:text-gray-100"
              :class="{ 'text-[32rpx]': !unitTop && type == 7, 'text-[36rpx]': !((!unitTop && type == 7)) }"
              v-for="(item, index) in hours" 
              :key="index"
            >
              {{ formatNum(item) }}
              <text class="text-[24rpx] pl-[8rpx] text-gray-500 dark:text-gray-400" v-if="!unitTop">时</text>
            </view>
          </picker-view-column>
          
          <!-- 分钟列 -->
          <picker-view-column v-if="(type == 1 || type > 3) && type != 8">
            <view 
              class="flex items-center justify-center text-gray-900 dark:text-gray-100"
              :class="{ 'text-[32rpx]': !unitTop && type == 7, 'text-[36rpx]': !((!unitTop && type == 7)) }"
              v-for="(item, index) in minutes" 
              :key="index"
            >
              {{ formatNum(item) }}
              <text class="text-[24rpx] pl-[8rpx] text-gray-500 dark:text-gray-400" v-if="!unitTop">分</text>
            </view>
          </picker-view-column>
          
          <!-- 秒数列 -->
          <picker-view-column v-if="type > 4 && type != 8">
            <view 
              class="flex items-center justify-center text-gray-900 dark:text-gray-100"
              :class="{ 'text-[32rpx]': !unitTop && type == 7, 'text-[36rpx]': !((!unitTop && type == 7)) }"
              v-for="(item, index) in seconds" 
              :key="index"
            >
              {{ formatNum(item) }}
              <text class="text-[24rpx] pl-[8rpx] text-gray-500 dark:text-gray-400" v-if="!unitTop">秒</text>
            </view>
          </picker-view-column>
        </picker-view>
      </view>
    </view>
  </view>
</template>

<script>
export default {
  name: 'DatetimePicker',
  emits: ['cancel', 'confirm'],
  props: {
    //0-年 1-日期+时间（年月日+时分） 2-日期(年月日) 3-日期(年月) 4-时间（时分） 5-时分秒 6-分秒 7-年月日 时分秒 8-年月日+小时
    type: {
      type: [Number, String],
      default: 1
    },
    //年份区间
    startYear: {
      type: Number,
      default: 1980
    },
    //年份区间
    endYear: {
      type: Number,
      default: 2050
    },
    hoursData: {
      type: Array,
      default() {
        return []
      }
    },
    minutesData: {
      type: Array,
      default() {
        return []
      }
    },
    secondsData: {
      type: Array,
      default() {
        return []
      }
    },
    //显示标题
    title: {
      type: String,
      default: ''
    },
    //标题字体大小
    titleSize: {
      type: [Number, String],
      default: 34
    },
    //标题字体颜色
    titleColor: {
      type: String,
      default: ''
    },
    //"取消"字体颜色
    cancelColor: {
      type: String,
      default: ''
    },
    //"确定"字体颜色
    color: {
      type: String,
      default: ''
    },
    //设置默认显示日期 2019-08-01 || 2019-08-01 17:01 || 2019/08/01
    setDateTime: {
      type: String,
      default: ''
    },
    //单位置顶
    unitTop: {
      type: Boolean,
      default: false
    },
    //圆角设置
    radius: {
      type: Boolean,
      default: false
    },
    //头部背景色
    headerBackground: {
      type: String,
      default: ''
    },
    //根据实际调整，不建议使用深颜色
    bodyBackground: {
      type: String,
      default: ''
    },
    //单位置顶时，单位条背景色
    unitBackground: {
      type: String,
      default: ''
    },
    height: {
      type: [Number, String],
      default: 520
    },
    //点击遮罩 是否可关闭
    maskClosable: {
      type: Boolean,
      default: true
    },
    zIndex: {
      type: [Number, String],
      default: 998
    }
  },
  data() {
    let immediate = true;
    // #ifdef MP-TOUTIAO
    immediate = false
    // #endif
    return {
      immediate,
      isShow: false,
      years: [],
      months: [],
      days: [],
      hours: [],
      minutes: [],
      seconds: [],
      year: 0,
      month: 0,
      day: 0,
      hour: 0,
      minute: 0,
      second: 0,
      startDate: '',
      endDate: '',
      value: [],
      isEnd: true,
      isChange: false,
      isSelect: false
    };
  },
  mounted() {
    this.$nextTick(() => {
      setTimeout(() => {
        this.initData();
      }, 20)
    })
  },
  computed: {
    yearOrMonth() {
      return `${this.year}-${this.month}`;
    },
    propsChange() {
      return `${this.type}-${this.startYear}-${this.endYear}-${this.hoursData}-${this.minutesData}-${this.secondsData}`;
    },
    getColor() {
      return this.color || 'var(--color-primary, #fcd34d)';
    },
    getMaskZIndex() {
      return Number(this.zIndex) + 1
    },
    getPickerZIndex() {
      return Number(this.zIndex) + 2
    }
  },
  watch: {
    yearOrMonth() {
      this.setDays();
    },
    propsChange() {
      if (this.isChange) return;
      this.isChange = true;
      this.$nextTick(() => {
        setTimeout(() => {
          this.isChange = false;
          this.initData();
        }, 50);
      })
    },
    setDateTime(val) {
      if (val && val !== true) {
        setTimeout(() => {
          this.initData();
        }, 20);
      }
    }
  },
  methods: {
    stop() {},
    formatNum: function(num) {
      return num < 10 ? '0' + num : num + '';
    },
    generateArray: function(start, end) {
      return Array.from(new Array(end + 1).keys()).slice(start);
    },
    getIndex: function(arr, val) {
      if (!arr || arr.length === 0 || val === undefined) return 0;
      let index = arr.indexOf(val);
      return index == -1 ? 0 : index;
    },
    getCharCount(str) {
      let regex = new RegExp('/', 'g');
      let result = str.match(regex);
      return !result ? 0 : result.length;
    },
    //日期时间处理
    initSelectValue() {
      let fdate = ''
      if (this.setDateTime && this.setDateTime !== true) {
        fdate = this.setDateTime.replace(/\-/g, '/');
        if (this.type == 3 && this.getCharCount(fdate) === 1) {
          fdate += '/01'
        } else if (this.type == 0) {
          fdate += '/01/01'
        }
        fdate = fdate && fdate.indexOf('/') == -1 ? `2023/01/01 ${fdate}` : fdate;
      }
      let time = null;
      if (fdate) time = new Date(fdate);
      else time = new Date();
      let year = time.getFullYear();
      if (year > this.endYear) {
        year = this.endYear
      } else if (year < this.startYear) {
        year = this.startYear
      }
      const month = time.getMonth() + 1;
      const day = time.getDate();
      const hour = time.getHours();
      const minute = time.getMinutes();
      const second = time.getSeconds();
      this.year = year;
      this.month = month;
      this.day = day;
      this.hour = hour;
      this.minute = minute;
      this.second = second;

      return [year, month, day, hour, minute, second]
    },
    initData() {
      const def = this.initSelectValue();
      const type = Number(this.type)
      switch (type) {
        case 0:
          this.setYears();
          break;
        case 1:
          this.setYears();
          this.setMonths();
          this.setDays();
          this.setHours();
          this.setMinutes();
          break;
        case 2:
          this.setYears();
          this.setMonths();
          this.setDays();
          break;
        case 3:
          this.setYears();
          this.setMonths();
          break;
        case 4:
          this.setHours();
          this.setMinutes();
          break;
        case 5:
          this.setHours();
          this.setMinutes();
          this.setSeconds();
          break;
        case 6:
          this.setMinutes();
          this.setSeconds();
          break;
        case 7:
          this.setYears();
          this.setMonths();
          this.setDays();
          this.setHours();
          this.setMinutes();
          this.setSeconds();
          break;
        case 8:
          this.setYears();
          this.setMonths();
          this.setDays();
          this.setHours();
          break;
        default:
          break;
      }
      this.$nextTick(() => {
        setTimeout(() => {
          this.setDefaultValues(def);
        }, 50)
      })
    },
    setDefaultValues(def) {
      let vals = []
      // 1-年月日+时分 2-年月日 3-年月 4-时分 5-时分秒 6-分秒 7-年月日 时分秒 8-年月日+小时
      const year = this.getIndex(this.years, def[0]);

      const month = this.getIndex(this.months, def[1])
      const day = this.getIndex(this.days, def[2])
      const hour = this.getIndex(this.hours, def[3])
      const minute = this.getIndex(this.minutes, def[4])
      const second = this.getIndex(this.seconds, def[5])

      const type = Number(this.type)
      switch (type) {
        case 0:
          vals = [year]
          break;
        case 1:
          vals = [year, month, day, hour, minute]
          break;
        case 2:
          vals = [year, month, day]
          break;
        case 3:
          vals = [year, month]
          break;
        case 4:
          vals = [hour, minute]
          break;
        case 5:
          vals = [hour, minute, second]
          break;
        case 6:
          vals = [minute, second]
          break;
        case 7:
          vals = [year, month, day, hour, minute, second]
          break;
        case 8:
          vals = [year, month, day, hour]
          break;
        default:
          break;
      }
      if (this.value.join(',') === vals.join(',')) return;
      setTimeout(() => {
        this.value = vals;
      }, 150);
    },
    setYears() {
      this.years = this.generateArray(this.startYear, this.endYear);
    },
    setMonths() {
      this.months = this.generateArray(1, 12);
    },
    setDays() {
      if (this.type == 3 || this.type == 4) return;
      let totalDays = new Date(this.year, this.month, 0).getDate();
      totalDays = !totalDays || totalDays < 1 ? 1 : totalDays
      this.days = this.generateArray(1, totalDays);
    },
    setHours() {
      if (this.hoursData && this.hoursData.length > 0) {
        this.hours = this.hoursData;
      } else {
        this.hours = this.generateArray(0, 23);
      }
    },
    setMinutes() {
      if (this.minutesData && this.minutesData.length > 0) {
        this.minutes = this.minutesData
      } else {
        this.minutes = this.generateArray(0, 59);
      }
    },
    setSeconds() {
      if (this.secondsData && this.secondsData.length > 0) {
        this.seconds = this.secondsData;
      } else {
        this.seconds = this.generateArray(0, 59);
      }
    },
    show() {
      setTimeout(() => {
        this.isShow = true;
      }, 250);
    },
    hide() {
      this.isShow = false;
      this.$emit('cancel', {});
    },
    maskClick() {
      if (!this.maskClosable) return;
      this.hide()
    },
    change(e) {
      this.value = e.detail.value;
      const type = Number(this.type)
      switch (type) {
        case 0:
          this.year = this.years[this.value[0]];
          break;
        case 1:
          this.year = this.years[this.value[0]];
          this.month = this.months[this.value[1]];
          this.day = this.days[this.value[2]];
          this.hour = this.hours[this.value[3]];
          this.minute = this.minutes[this.value[4]];
          break;
        case 2:
          this.year = this.years[this.value[0]];
          this.month = this.months[this.value[1]];
          this.day = this.days[this.value[2]];
          break;
        case 3:
          this.year = this.years[this.value[0]];
          this.month = this.months[this.value[1]];
          break;
        case 4:
          this.hour = this.hours[this.value[0]];
          this.minute = this.minutes[this.value[1]];
          break;
        case 5:
          this.hour = this.hours[this.value[0]];
          this.minute = this.minutes[this.value[1]];
          this.second = this.seconds[this.value[2]];
          break;
        case 6:
          this.minute = this.minutes[this.value[0]];
          this.second = this.seconds[this.value[1]];
          break;
        case 7:
          this.year = this.years[this.value[0]];
          this.month = this.months[this.value[1]];
          this.day = this.days[this.value[2]];
          this.hour = this.hours[this.value[3]];
          this.minute = this.minutes[this.value[4]];
          this.second = this.seconds[this.value[5]];
          break;
        case 8:
          this.year = this.years[this.value[0]];
          this.month = this.months[this.value[1]];
          this.day = this.days[this.value[2]];
          this.hour = this.hours[this.value[3]];
          break;
        default:
          break;
      }
      this.isEnd = true
    },
    selectResult() {
      let result = {};
      let year = this.year;
      let month = this.formatNum(this.month || 0);
      let day = this.formatNum(this.day || 0);
      let hour = this.formatNum(this.hour || 0);
      let minute = this.formatNum(this.minute || 0);
      let second = this.formatNum(this.second || 0);
      const type = Number(this.type)
      switch (type) {
        case 0:
          result = {
            year: year,
            result: year
          };
          break;
        case 1:
          result = {
            year: year,
            month: month,
            day: day,
            hour: hour,
            minute: minute,
            result: `${year}-${month}-${day} ${hour}:${minute}`
          };
          break;
        case 2:
          result = {
            year: year,
            month: month,
            day: day,
            result: `${year}-${month}-${day}`
          };
          break;
        case 3:
          result = {
            year: year,
            month: month,
            result: `${year}-${month}`
          };
          break;
        case 4:
          result = {
            hour: hour,
            minute: minute,
            result: `${hour}:${minute}`
          };
          break;
        case 5:
          result = {
            hour: hour,
            minute: minute,
            second: second,
            result: `${hour}:${minute}:${second}`
          };
          break;
        case 6:
          result = {
            minute: minute,
            second: second,
            result: `${minute}:${second}`
          };
          break;
        case 7:
          result = {
            year: year,
            month: month,
            day: day,
            hour: hour,
            minute: minute,
            second: second,
            result: `${year}-${month}-${day} ${hour}:${minute}:${second}`
          };
          break;
        case 8:
          result = {
            year: year,
            month: month,
            day: day,
            hour: hour,
            result: `${year}-${month}-${day} ${hour}:00`
          };
          break;
        default:
          break;
      }
      this.$emit('confirm', result);
    },
    waitFix(index = 0) {
      if (this.isEnd) {
        this.selectResult()
      } else {
        index++;
        if (index >= 20) {
          this.isEnd = true
        }
        setTimeout(() => {
          this.waitFix(index)
        }, 50)
      }
    },
    btnFix() {
      setTimeout(() => {
        this.waitFix()
        this.hide();
      }, 80);
    },
    pickerstart() {
      this.isEnd = false
    }
  }
};
</script>
